using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Net;
using System.Windows.Forms;
using System.Xml.Serialization;
using Krilib.Bridges;
using Krilib.Data;
using Krile.Cores.PManElems;
using Im = Krile.Imported;

namespace Krile.Cores
{
    /// <summary>
    /// Configuration class
    /// </summary>
    public sealed class Config
    {
        public Config() { }

        private Config(bool first) : this()
        {
            this.isfirst = first;
        }

        #region Automation

        /// <summary>
        /// Config file path
        /// </summary>
        private static string fpath { get { return System.IO.Path.Combine(Define.AppPath, Define.ConfigFileName); } }

        private static string spath { get { return System.IO.Path.Combine(Define.AppPath, Define.StateFileName); } }
        /// <summary>
        /// Load/init config
        /// </summary>
        /// <returns>config class instance</returns>
        static public Config Load()
        {
            try
            {
                if (System.IO.File.Exists(fpath))
                    return Im.Snippets.Files.LoadXML<Config>(fpath, false);
                else
                    return new Config(true);
            }
            catch (Exception e)
            {
                Subsystem.Debugger.AddReport(new DebugReport(e, DebugReport.Priorities.Warn));
                System.Windows.Forms.MessageBox.Show(Lang.Msg.Config_Load_Failed,
                    Define.ApplicationName + " - Configuration Load Error",
                    System.Windows.Forms.MessageBoxButtons.OK,
                    System.Windows.Forms.MessageBoxIcon.Warning);
#if DEBUG
                return new Config();
                throw e;
#else
                return new Config();
#endif
            }
        }

        /// <summary>
        /// Load/init state
        /// </summary>
        public void LoadState()
        {
            try
            {
                if (System.IO.File.Exists(spath))
                    State = Im.Snippets.Files.LoadXML<_State>(spath, false);
                else
                    State = new _State();
            }
            catch (Exception e)
            {
                Subsystem.Debugger.AddReport(new DebugReport(e, DebugReport.Priorities.Warn));
                System.Windows.Forms.MessageBox.Show(Lang.Msg.State_Load_Failed,
                    Define.ApplicationName + " - Previous State Load Error",
                    System.Windows.Forms.MessageBoxButtons.OK,
                    System.Windows.Forms.MessageBoxIcon.Warning);
#if DEBUG
                throw e;
#else
                this.State = new _State();
#endif
            }
        }

        /// <summary>
        /// Save config
        /// </summary>
        public void Save()
        {
            try
            {
                Im.Snippets.Files.SaveXML<_State>(spath, this.State);
                Im.Snippets.Files.SaveXML<Config>(fpath, this);
            }
            catch (Exception e)
            {
                Subsystem.Debugger.AddReport(new DebugReport(e, DebugReport.Priorities.Warn));
#if DEBUG
                throw e;
#endif
            }
        }

        private bool isfirst = false;
        /// <summary>
        /// Check firstboot
        /// </summary>
        public bool IsFirstboot
        {
            get { return isfirst; }
        }

        #endregion

        #region Appearance Property
        public _Appearance Appearance = new _Appearance();
        [EditorBrowsable(EditorBrowsableState.Never)]
        public class _Appearance
        {
            /// <summary>
            /// System Base Color Configuration
            /// </summary>
            public _BaseColorConfig BaseColorConfig = new _BaseColorConfig();
            public class _BaseColorConfig
            {
                /// <summary>
                /// Foreground color
                /// </summary>
                public Im.Data.XColor ForeColor = new Im.Data.XColor(Color.Black);

                /// <summary>
                /// Secondary fore color
                /// </summary>
                public Im.Data.XColor ForeSecondaryColor = new Im.Data.XColor(Color.DimGray);

                /// <summary>
                /// Link text foreground color
                /// </summary>
                public Im.Data.XColor LinkTextColor = new Im.Data.XColor(Color.Blue);

                /// <summary>
                /// Background color in list
                /// </summary>
                public Im.Data.XColor ListBackgroundColor = new Im.Data.XColor(Color.White);

            }

            /// <summary>
            /// Renderer Config
            /// </summary>
            public _Renderer Renderer = new _Renderer();
            public class _Renderer
            {
                /// <summary>
                /// Color config
                /// </summary>
                public _Colors Colors = new _Colors();
                public class _Colors
                {
                    /// <summary>
                    /// Alternate background color in list
                    /// </summary>
                    public Data.SXColor ListAlternateBackgroundColor = new Data.SXColor(Color.FromArgb(230, 230, 230));

                    /// <summary>
                    /// Reply foreground color
                    /// </summary>
                    public Im.Data.XColor ListReplyTextColor = new Im.Data.XColor(Color.DimGray);

                    /// <summary>
                    /// Not-found reply foreground color
                    /// </summary>
                    public Im.Data.XColor ListReplyNotfoundTextColor = new Im.Data.XColor(Color.Gray);

                    /// <summary>
                    /// Reply background color
                    /// </summary>
                    public Im.Data.XColor ListReplyBackgroundColor = new Im.Data.XColor(Color.Moccasin);

                    /// <summary>
                    /// Header/footer background color
                    /// </summary>
                    public Im.Data.XColor ListHeaderFooterBackgroundColor = new Im.Data.XColor(Color.Gray);

                    /// <summary>
                    /// Header/footer text color
                    /// </summary>
                    public Im.Data.XColor ListHeaderFooterTextColor = new Im.Data.XColor(Color.White);

                    /// <summary>
                    /// Newest receive background color
                    /// </summary>
                    public Data.SXColor ListNewestBackgroundColor = new Data.SXColor(Color.FromArgb(200, 255, 170));

                    /// <summary>
                    /// List background color for same user who post selected status
                    /// </summary>
                    public Data.SXColor ListSelectedUserBackgroundColor = new Data.SXColor(Color.FromArgb(200, 200, 255));

                    /// <summary>
                    /// List background color for user who reply to selected status
                    /// </summary>
                    public Data.SXColor ListReplyToSelectedBackgroundColor = new Data.SXColor(Color.FromArgb(255, 255, 150));

                    /// <summary>
                    /// List background color for user who reply from selected status
                    /// </summary>
                    public Data.SXColor ListReplyFromSelectedBackgroundColor = new Data.SXColor(Color.FromArgb(140, 255, 230));

                    /// <summary>
                    /// List background color for status which reply to you
                    /// </summary>
                    public Data.SXColor ListReplyToMeBackgroundColor = new Data.SXColor(Color.FromArgb(255, 160, 255), false);

                    /// <summary>
                    /// List background color for status which reply to you and newest receive
                    /// </summary>
                    public Data.SXColor ListReplyToMeNewestBackgroundColor = new Data.SXColor(Color.FromArgb(255, 160, 160));

                    /// <summary>
                    /// List background color for user post
                    /// </summary>
                    public Data.SXColor ListMyPostBackgroundColor = new Krile.Data.SXColor(Color.FromArgb(200, 255, 255));

                }

                /// <summary>
                /// Detail config
                /// </summary>
                public _Detail Detail = new _Detail();
                public class _Detail
                {
                    /// <summary>
                    /// Normal list height
                    /// </summary>
                    public int NormalListHeight = 22;

                    /// <summary>
                    /// Selected list min-height
                    /// </summary>
                    public int SelectedListMinHeight = 40;

                    /// <summary>
                    /// Format for show datetime
                    /// </summary>
                    public string DateTimeFormat = " - yy/MM/dd(ddd) HH:mm:ss";

                    /// <summary>
                    /// Margin for drawing
                    /// </summary>
                    public int TextRenderingMargin = 2;
                }

                /// <summary>
                /// User name area
                /// </summary>
                public int UserNameArea = 160;

                /// <summary>
                /// Show user's mini icon in normal list 
                /// </summary>
                public bool UseListMiniIcon = true;

                /// <summary>
                /// Show user id in selected status
                /// </summary>
                public bool ShowUserId = false;

                /// <summary>
                /// Status Tool-tip Newline character width
                /// </summary>
                public int TooltipNewlineCount = 40;

                /// <summary>
                /// Centering user-name text(in normal state)
                /// </summary>
                public bool UserNameCentering = false;

                /// <summary>
                /// Name render area puts on above
                /// </summary>
                public bool NameAbove = false;
            }

            /// <summary>
            /// Tab appearance config
            /// </summary>
            public _TabAppearance TabAppearance = new _TabAppearance();
            public class _TabAppearance
            {
                /// <summary>
                /// Tab size(height is fixed,and width is maximum size)
                /// </summary>
                public Size MaxSize = new Size(200, 25);

                /// <summary>
                /// Tab width force set to maxsize
                /// </summary>
                public bool FixedSize = false;

                /// <summary>
                /// Multiline mode
                /// </summary>
                public bool UseMultiline = true;

                /// <summary>
                /// Show tab close button for all tab
                /// </summary>
                public bool ShowCloseButtonForAllTab = false;

                /// <summary>
                /// Show Tab List Button
                /// </summary>
                public bool ShowTabListButton = true;

                /// <summary>
                /// ATL Tab Name
                /// </summary>
                public string ATLTabName = "All Timeline";
            }

            /// <summary>
            /// Krile system default font
            /// </summary>
            public Im.Data.XFont Font = new Im.Data.XFont(Control.DefaultFont);

            /// <summary>
            /// Image interpolation mode
            /// </summary>
            public InterpolationMode InterpolateMode = InterpolationMode.HighQualityBicubic;

            public enum ToolStripDesigns { Blue, Black, Silver, Professional, System };
            /// <summary>
            /// Tool strip design
            /// </summary>
            public ToolStripDesigns ToolStripDesign = ToolStripDesigns.Blue;

            /// <summary>
            /// Timeline list scrollbar width
            /// </summary>
            public int ScrollbarWidth = 18;

        }
        #endregion

        #region Network Property
        public _Network Network = new _Network();
        [EditorBrowsable(EditorBrowsableState.Never)]
        public class _Network
        {
            #region IWebProxy Proxy
            /// <summary>
            /// Web Proxy
            /// </summary>
            [XmlIgnore()]
            public IWebProxy WebProxy = WebRequest.DefaultWebProxy;

            [EditorBrowsable(EditorBrowsableState.Never)]
            public _ProxyState ProxyState
            {
                get { return new _ProxyState(WebProxy); }
                set { WebProxy = value.ReflectCfgParam(); }
            }

            [EditorBrowsable(EditorBrowsableState.Never)]
            public class _ProxyState
            {
                public enum DefaultState { Default, Null, Set };
                public DefaultState Default = DefaultState.Default;
                public string Address = String.Empty;
                public string[] BypassList = new string[0];
                public bool BypassOnlyLocal = false;

                public _ProxyState(IWebProxy iwp)
                {
                    if (iwp == WebRequest.DefaultWebProxy)
                        Default = DefaultState.Default;
                    else if (iwp == null)
                        Default = DefaultState.Null;
                    else
                    {
                        Default = DefaultState.Set;
                        Address = ((WebProxy)iwp).Address.OriginalString;
                        BypassList = ((WebProxy)iwp).BypassList;
                        BypassOnlyLocal = ((WebProxy)iwp).BypassProxyOnLocal;
                    }
                }
                public _ProxyState() { }
                public IWebProxy ReflectCfgParam()
                {
                    if (Default == DefaultState.Default) return WebRequest.DefaultWebProxy;
                    if (Default == DefaultState.Null) return null;
                    WebProxy ret = new WebProxy(Address, BypassOnlyLocal, BypassList);
                    return (IWebProxy)ret;
                }
            }
            #endregion

            /// <summary>
            /// Web connection timeout
            /// </summary>
            public int Timeout = 30000;

            /// <summary>
            /// Web browser path (String.Empty uses default)
            /// </summary>
            public string BrowserPath = String.Empty;

            /// <summary>
            /// Maximum image parallel download
            /// </summary>
            public int ImgParallelDlMax = 5;

            /// <summary>
            /// Use GZip on http-connect
            /// </summary>
            public bool UseGZipCompression = true;
        }

        #endregion

        #region Timeline Property

        public _Timeline Timeline = new _Timeline();
        public class _Timeline
        {
            /// <summary>
            /// NG Cluster
            /// </summary>
            [XmlIgnore()]
            public SearchDataCluster NGSDClusters
            {
                get { return Core.Config.State.NGSDClusters; }
                set { Core.Config.State.NGSDClusters = value; }
            }

            /// <summary>
            /// Add new timeline to list bottom
            /// </summary>
            public bool ListBottomNewer = false;

            /// <summary>
            /// Enable read management
            /// </summary>
            public bool ManageReadFlags = true;

        }
        #endregion

        #region Notification Property
        public _Notification Notification = new _Notification();
        [EditorBrowsable(EditorBrowsableState.Never)]
        public class _Notification
        {
            /// <summary>
            /// Show balloon tooltip on status received
            /// </summary>
            public bool ShowBalloonOnStatusReceived = true;

            /// <summary>
            /// num of statuses show in balloon
            /// </summary>
            public int BalloonStatusNum = 3;

            /// <summary>
            /// num of statuse's quote length which show in balloon
            /// </summary>
            public int BalloonStatusQuoteLength = 20;

            /// <summary>
            /// Show window automatic on status received
            /// </summary>
            public bool FormAutoForeground = false;

            /// <summary>
            /// Cancel show balloon on window shown
            /// </summary>
            public bool CancelBalloonOnWindowShown = false;

            /// <summary>
            /// Play sound with some behavior(ex:receive new,receive reply,etc...)
            /// </summary>
            public bool PlaySound = true;

            /// <summary>
            /// Notification Interval(sec)
            /// </summary>
            public int NotificationInterval = 60;

            /// <summary>
            /// Notification interval apply for all
            /// </summary>
            public bool IntervalApplyForAll = false;
        }

        #endregion

        #region Security Property
        public _Security Security = new _Security();
        [EditorBrowsable(EditorBrowsableState.Never)]
        public class _Security
        {
            /// <summary>
            /// Using strict security mode
            /// </summary>
            public bool StrictSecurity = false;

            #region Basic Security Entities

            /// <summary>
            /// Crypto key
            /// </summary>
            public string cryptokey = null;

            #endregion

            #region Strict Security

            /// <summary>
            /// Key hash with SHA-512
            /// </summary>
            public string KeyHash = null;

            #endregion

            #region Plugin Security

            [XmlIgnore()]
            public string[] PluginAuthSerializeKeyBuffer = null;

            /// <summary>
            /// Authorized plugin
            /// </summary>
            public string[] PluginAuthEncryptedStr
            {
                get { return Core.PluginManager.PluginAuth.SerializeEncryptedKeys; }
                set { PluginAuthSerializeKeyBuffer = value; }
            }

            #endregion

            /// <summary>
            ///  Report ignore data
            /// </summary>
            public ReportIgnoreData[] Ignores = null;

            /// <summary>
            /// Report ignore data
            /// </summary>
            public class ReportIgnoreData
            {
                public bool IsException { get; set; }
                public string Message { get; set; }
                public string MethodName { get; set; }
                public Krilib.Bridges.DebugReport.Priorities Priority { get; set; }

                public ReportIgnoreData()
                {
                    IsException = false;
                    Message = null;
                    MethodName = null;
                    Priority = DebugReport.Priorities.Note;
                }

                public ReportIgnoreData(Krilib.Bridges.DebugReport report)
                {
                    IsException = report.IsExceptionReport;
                    Priority = report.Priority;
                    Message = report.Message;
                    if (IsException)
                        MethodName = report.Exception.TargetSite.DeclaringType.FullName + "." + report.Exception.TargetSite.Name;
                    else
                        MethodName = null;
                }

                public bool IsIgnoreReport(Krilib.Bridges.DebugReport report)
                {
                    if (report.IsExceptionReport != IsException)
                        return false;
                    if (report.Message != this.Message)
                        return false;
                    if (report.Priority != Priority)
                        return false;
                    if (report.IsExceptionReport &&
                        report.Exception.TargetSite.DeclaringType.FullName + "." + report.Exception.TargetSite.Name != MethodName)
                        return false;
                    return true;
                }

                public override string ToString()
                {
                    return Enum.GetName(typeof(Krilib.Bridges.DebugReport.Priorities), Priority) + " -" + Message;
                }
            }
        }

        #endregion

        #region Behavior Property
        public _Behavior Behavior = new _Behavior();
        [EditorBrowsable(EditorBrowsableState.Never)]
        public class _Behavior
        {
            /// <summary>
            /// Show mainwindow on startup
            /// </summary>
            public bool ShowMainWindowOnStartup = true;

            /// <summary>
            /// Show splash screen
            /// </summary>
            /// <remarks>
            /// This configuration saves as ".splash" file.
            /// </remarks>
            [XmlIgnore()]
            public bool ShowSplashScreen
            {
                get
                {
                    return File.Exists(Path.Combine(Application.StartupPath, Define.SplashConfigFileName));
                }
                set
                {
                    if (ShowSplashScreen == value) return;
                    if (value)
                    {
                        File.Create(Path.Combine(Application.StartupPath, Define.SplashConfigFileName));
                    }
                    else
                    {
                        File.Delete(Path.Combine(Application.StartupPath, Define.SplashConfigFileName));
                    }
                }
            }

            /// <summary>
            /// Send tray on minimize
            /// </summary>
            public bool SendTrayOnMinimize = false;

            /// <summary>
            /// Exit on main window close
            /// </summary>
            public bool ExitOnWindowClose = false;

            /// <summary>
            /// Picture keeping limit
            /// </summary>
            public int PictureSaveLimitMinutes = 10;

            /// <summary>
            /// Check update automatically on startup
            /// </summary>
            public bool CheckUpdateOnStartup = true;

            /// <summary>
            /// Save error reporting
            /// </summary>
            public bool SaveErrorReport = true;

            /// <summary>
            /// Confirm before close timeline tab
            /// </summary>
            public bool ConfirmOnCloseTab = false;

            /// <summary>
            /// Reload timeline on gtlstate changed
            /// </summary>
            public bool ReloadOnGTLImplyStateChanged = false;

            /// <summary>
            /// Auto close postbox after posted
            /// </summary>
            public bool ClosePostboxAfterPost = true;

            /// <summary>
            /// Reply auto clear after postbox closed
            /// </summary>
            public bool ClearReplyOnClosePostBox = true;
        }

        #endregion

        #region Key Assign Property
        public _KeyAssign KeyAssign = new _KeyAssign();
        [EditorBrowsable(EditorBrowsableState.Never)]
        public class _KeyAssign
        {
            /// <summary>
            /// Data for key assign
            /// </summary>
            public KeyAssignElems.KeyAssignData[] KeyAssignData
            {
                get { return Core.KeyAssign.AssignDataArray; }
                set { Core.KeyAssign.AssignDataArray = value; }
            }
        }

        #endregion

        #region Advanced Property
        public _Advanced Advanced = new _Advanced();
        [EditorBrowsable(EditorBrowsableState.Never)]
        public class _Advanced
        {
            /// <summary>
            /// MainWindow background state re-init wait
            /// </summary>
            public int BackStateReinitWait = 3000;

            /// <summary>
            /// Check application duplicated execution by mutex.
            /// </summary>
            public bool CheckAppDuplicateExec = true;

            /// <summary>
            /// Change selected list height
            /// </summary>
            public int SelectedListNameCommandHeight = 22;

            /// <summary>
            /// Internal pict. default size
            /// </summary>
            public Size InternalPictureDefaultSizeMax = new Size(100, 100);
        }
        #endregion

        #region State Property
        //State configuration must saving separated with Config.
        //This prop will read with delay.
        [XmlIgnore()]
        public _State State = new _State();
        [EditorBrowsable(EditorBrowsableState.Never)]
        public class _State
        {
            /// <summary>
            /// NG Cluster
            /// </summary>
            public SearchDataCluster NGSDClusters = null;

            public Rectangle WindowRect
            {
                get
                {
                    return Im.Snippets.WinForms.GetNormalWindowLocation(Core.FormManager.MainForm);
                }
                set
                {
                    //Tips:using DesktopLocation for be sure to put window on same place
                    Core.FormManager.MainForm.DesktopLocation = value.Location;
                    Core.FormManager.MainForm.Size = value.Size;
                }
            }

            public FormWindowState WindowState
            {
                get { return Core.FormManager.MainForm.WindowState; }
                set { Core.FormManager.MainForm.WindowState = value; }
            }

            public int MainSplitOffset = 200;

            public int[] StatusSplitOffsets = null;

            public bool ShowPostBox = false;

            public bool PostBoxInTop = false;

            public bool SilentMode = false;

            public bool ShowMenubar = true;

            public bool ShowToolbar = true;

            public bool ShowStatusbar = true;

            public bool RecvGTL = false;

            [XmlIgnore()]
            public Color CurrentForeColor = Color.Black;

            public bool TopMostMainWindow
            {
                get { return Core.FormManager.MainForm.TopMost; }
                set { Core.FormManager.MainForm.TopMost = value; }
            }

            public Data.TabData[] TabDatas = null;
        }
        #endregion
    }

    /// <summary>
    /// Confuguration bridge class
    /// </summary>
    public sealed class ConfigBridge : IConfig
    {
        public Color CurrentStatusForeColor
        {
            get { return Core.Config.Appearance.BaseColorConfig.ForeColor.Value; }
        }

        public int DrawMargin
        {
            get { return 2; }
        }

        public Font Font
        {
            get { return Core.Config.Appearance.Font.Value; }
        }

        public Color ForeColor
        {
            get { return Core.Config.Appearance.BaseColorConfig.ForeColor.Value; }
        }

        public Color ForeSecondaryColor
        {
            get { return Core.Config.Appearance.BaseColorConfig.ForeSecondaryColor.Value; }
        }

        public System.Drawing.Drawing2D.InterpolationMode ImageInterpolation
        {
            get { return Core.Config.Appearance.InterpolateMode; }
        }

        public Color LinkColor
        {
            get { return Core.Config.Appearance.BaseColorConfig.LinkTextColor.Value; }
        }

        public IWebProxy Proxy
        {
            get { return Core.Config.Network.WebProxy; }
        }

        public int Timeout
        {
            get { return Core.Config.Network.Timeout; }
        }

        public bool UseGZip
        {
            get { return Core.Config.Network.UseGZipCompression; }
        }

        public string DefaultUserAgent
        {
            get { return Define.UserAgent; }
        }

        public string PluginPath
        {
            get { return System.IO.Path.Combine(Define.AppPath, Define.PluginDir); }
        }

        public string AppName
        {
            get { return Define.ApplicationName; }
        }

        public Size ImageDefaultMaxSize
        {
            get { return Core.Config.Advanced.InternalPictureDefaultSizeMax; }
        }
    }
}
